//二维图像处理
import './style/index.less';
import webglUtils from './ThirdParty/webgl-utils';

import VS from './Shaders/demo3VS.glsl';
import FS from './Shaders/demo3FS.glsl';

function render(image) {
    const canvas = document.getElementById("canvas");
    const gl = canvas.getContext('webgl2');
    if (!gl) {
        console.log('webgl2 not supported');
    }

    const program = webglUtils.createProgramFromSources(gl, [VS, FS]);

    //attribute和uniform的位置
    const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
    const texCoordAttributeLocation = gl.getAttribLocation(program, "a_texCoord");
    const resolutionLocation = gl.getUniformLocation(program, "u_resolution");
    const imageLocation = gl.getUniformLocation(program, "u_image");

    //kernel状态uniform的内存位置
    const kernelLocation = gl.getUniformLocation(program, "u_kernel[0]");
    const kernelWeightLocation = gl.getUniformLocation(program, "u_kernelWeight");
    const flipYLocation = gl.getUniformLocation(program, "u_flipY");

    //attribute的状态
    const vao = gl.createVertexArray();
    //关联当前使用这个vao
    gl.bindVertexArray(vao);

    //创建position数据的buffer
    const positionBuffer = gl.createBuffer();
    //启用position attribute
    gl.enableVertexAttribArray(positionAttributeLocation);
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

    //告诉attribute如何从positionBuffer读取数据
    const size1 = 2;
    const type1 = gl.FLOAT;
    const normalize1 = false;
    const stride1 = 0;
    const offset1 = 0;
    gl.vertexAttribPointer(positionAttributeLocation, size1, type1, normalize1, stride1, offset1);

    //创建texture coordinates的buffer
    const texCoordBuffer = gl.createBuffer();
    gl.enableVertexAttribArray(texCoordAttributeLocation);
    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
    //存入数据
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        0, 0,
        1, 0,
        0, 1,
        0, 1,
        1, 0,
        1, 1
    ]), gl.STATIC_DRAW);
    const size2 = 2;
    const type2 = gl.FLOAT;
    const normalize2 = false;
    const stride2 = 0;
    const offset2 = 0;
    gl.vertexAttribPointer(texCoordAttributeLocation, size2, type2, normalize2, stride2, offset2);

    //创建材质
    const originalImageTexture = createAndSetupTexture(gl);

    //将image传入texture
    const mipLevel = 0;
    const internalFormat = gl.RGBA;
    const srcFormat = gl.RGBA;
    const srcType = gl.UNSIGNED_BYTE;
    gl.texImage2D(gl.TEXTURE_2D, mipLevel, internalFormat, srcFormat, srcType, image);

    //创建两个texture，与framebuffer关联
    let textures = [];
    let framebuffers = [];
    for (let ii = 0; ii < 2; ii++) {
        let texture = createAndSetupTexture(gl);
        textures.push(texture);

        //将texture的大小设置成与image一样
        const mipLevel = 0;
        const internalFormat = gl.RGBA;
        const border = 0;
        const srcFormat = gl.RGBA;
        const srcType = gl.UNSIGNED_BYTE;
        const data = null;
        gl.texImage2D(gl.TEXTURE_2D, mipLevel, internalFormat, image.width, image.height, border, srcFormat, srcType, data);

        //创建framebuffer
        const fbo = gl.createFramebuffer();
        framebuffers.push(fbo);
        gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);

        //将texture和framebuffer关联
        const attachmentPoint = gl.COLOR_ATTACHMENT0;
        gl.framebufferTexture2D(gl.FRAMEBUFFER, attachmentPoint, gl.TEXTURE_2D, texture, mipLevel);
    }

    //激活position buffer，在setRectangle中用
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    //设置画框（两个三角形）的position
    setRectangle(gl, 0, 0, image.width, image.height);

    // Define several convolution kernels
    var kernels = {
        normal: [
            0, 0, 0,
            0, 1, 0,
            0, 0, 0
        ],
        gaussianBlur: [
            0.045, 0.122, 0.045,
            0.122, 0.332, 0.122,
            0.045, 0.122, 0.045
        ],
        unsharpen: [
            -1, -1, -1,
            -1, 9, -1,
            -1, -1, -1
        ],
        emboss: [
            -2, -1, 0,
            -1, 1, 1,
            0, 1, 2
        ]
    };

    drawEffects();


    function createAndSetupTexture(gl) {
        var texture = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_2D, texture);

        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

        return texture;
    }

    function drawEffects() {
        //调整分辨率与canvas大小相等
        webglUtils.resizeCanvasToDisplaySize(gl.canvas);
        //调整webgl画布大小与canvas大小相等
        gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
        gl.clearColor(0, 0, 0, 0);
        gl.clear(gl.COLOR_BUFFER_BIT);

        //使用创建的以上的program
        gl.useProgram(program);

        //这里需要再次关联吗？
        gl.bindVertexArray(vao);

        //在unit 0 上开始用原始image
        gl.activeTexture(gl.TEXTURE0 + 0);
        gl.bindTexture(gl.TEXTURE_2D, originalImageTexture);

        //告诉shader在unit 0的位置获取texture
        gl.uniform1i(imageLocation, 0);

        //画在texture上时,不用flipY
        gl.uniform1f(flipYLocation, 1);

        let count = 0;
        for(let filterName in kernels){
            /**Filter使用开始 */
            setFramebuffer(framebuffers[count%2], image.width, image.height);

            drawWithKernel(filterName);

            //下一次绘制使用当前framebuffer对应的texture
            gl.bindTexture(gl.TEXTURE_2D, textures[count%2]);
            /**Filter使用结束 */
            count++;
        }
        

        gl.uniform1f(flipYLocation, -1);//为了canvas再把画布y倒置一次
        setFramebuffer(null, gl.canvas.width, gl.canvas.height);

        drawWithKernel("normal");
    }

    function setFramebuffer(fbo, width, height) {
        //将当前画面渲染到这本fbo上
        gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
        //告诉shader当前framebuffer的分辨率
        gl.uniform2f(resolutionLocation, width, height);
        //将裁剪空间调整到像素空间
        gl.viewport(0, 0, width, height);
    }

    function drawWithKernel(name) {
        //设置kernel和它的权重
        gl.uniform1fv(kernelLocation, kernels[name]);
        gl.uniform1f(kernelWeightLocation, computeKernelWeight(kernels[name]));

        //绘制方形画布
        const primitiveType = gl.TRIANGLES;
        const offset3 = 0;
        const count = 6;
        gl.drawArrays(primitiveType, offset3, count);
    }

    function computeKernelWeight(kernel) {
        let weight = kernel.reduce((prev, curr) => {
            return prev + curr;
        });
        return weight <= 0 ? 1 : weight;
    }
}

function main() {
    const image = new Image();
    image.src = require('./assets/1552984768637.jpg');
    image.onload = () => {
        render(image);
    }
}

function setRectangle(gl, x, y, width, height) {
    var x1 = x;
    var x2 = x + width;
    var y1 = y;
    var y2 = y + height;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        x1, y1,
        x2, y1,
        x1, y2,
        x1, y2,
        x2, y1,
        x2, y2,
    ]), gl.STATIC_DRAW);
}

main();